﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ServiceBus.Contract;
using System.Threading;
using System.Runtime.Serialization;

namespace ServiceBus.Service
{
    /// <summary>
    /// Define a certain kind of message
    /// </summary>
    [DataContract]
    [Serializable]
    public class MessageBox
    {
        #region Properties
       
        /// <summary>
        /// To distinguish message
        /// </summary>
        [DataMember]
        public string FunctionCode { get; set; }
        /// <summary>
        /// catelog name
        /// </summary>
        [DataMember]
        public string Name { get; set; }
        /// <summary>
        /// catelog description
        /// </summary>
        public string Description { get; set; }
        /// <summary>
        /// if this catelog will send wcf message
        /// </summary>
        [DataMember]
        public bool MessageEnable { get; set; }
        /// <summary>
        /// if this catelog will send email
        /// </summary>
        [DataMember]
        public bool EmailEnable { get; set; }
        /// <summary>
        /// if this database will save into database
        /// </summary>
        [DataMember]
        public bool DatabaseEnable { get; set; }
        [DataMember]
        public string DefaultEmailAddress { get; set; }

        public static List<MessageBox> MessageBoxes { get; private set; }
        #endregion

        #region Events
        public delegate void MessageHandle(MessageArg e);
        public delegate void MessageErrHandle(MessageArg e, Exception exception);
        public delegate void MesageBoxPersistence(List<MessageBox> messageboxes);

        /// <summary>
        /// event before sending message
        /// </summary>
        public static event MessageHandle BeforeMessage;
        /// <summary>
        /// event after sending message
        /// </summary>
        public static event MessageHandle AfterMessage;
        /// <summary>
        /// event when error occur in sending message
        /// </summary>
        public static event MessageErrHandle AfterMessageError;

        /// <summary>
        /// event when loading messageboxes. in order to get saved messageboxes from external code
        /// </summary>
        public static event MesageBoxPersistence LoadingEvent;
        /// <summary>
        /// event when saving messageboxes. in order to save messageboxes from external code
        /// </summary>
        public static event MesageBoxPersistence SavingEvent;
        #endregion

        #region Static Methods
        /// <summary>
        /// static constructor
        /// </summary>
        static MessageBox()
        {
            MessageBoxes = new List<MessageBox>();
        }
        /// <summary>
        /// get messagebox from functioncode
        /// </summary>
        /// <param name="functionCode">given functioncode</param>
        /// <returns>messagebox object</returns>
        public static MessageBox GetMessageBoxByFunctionCode(string functionCode)
        {
            try
            {
                return MessageBoxes.SingleOrDefault<MessageBox>(item => item.FunctionCode == functionCode);
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// add a new messagebox
        /// </summary>
        /// <param name="messageBox">new messagebox</param>
        public static void AddMessageBox(MessageBox messageBox)
        {
            if (MessageBoxes == null) MessageBoxes = new List<MessageBox>();
            if (string.IsNullOrEmpty(messageBox.FunctionCode)) throw new ArgumentNullException("messageBox.FunctionCode is null");
            if (string.IsNullOrEmpty(messageBox.Name)) throw new ArgumentNullException("messageBox.Name is null");
            if (GetMessageBoxByFunctionCode(messageBox.FunctionCode) != null) throw new ArgumentNullException("FunctionCode is not unique");
           
            Monitor.Enter(MessageBoxes);
            MessageBoxes.Add(messageBox);
            Monitor.Exit(MessageBoxes);
        }

        /// <summary>
        /// remove messagebox from functioncode
        /// </summary>
        /// <param name="functionCode">functioncode needs to be removed</param>
        public static void RemoveMessageBoxByFunction(string functionCode)
        {
            if (MessageBoxes == null) return;
            Monitor.Enter(MessageBoxes);
            MessageBoxes.RemoveAll(item => item.FunctionCode == functionCode);
            Monitor.Exit(MessageBoxes);
        }

        /// <summary>
        /// load messagebox from external code
        /// </summary>
        public static void LoadingMessageBoxes()
        {
            if (MessageBoxes == null) MessageBoxes = new List<MessageBox>();
            if (LoadingEvent != null) LoadingEvent(MessageBoxes);
        }
        /// <summary>
        /// save messagebox from external code
        /// </summary>
        public static void SavingMessageBoxes()
        {
            if (SavingEvent != null) SavingEvent(MessageBoxes);
        }
        
        #endregion

        #region Methods
        public MessageBox(string functioncode)
        {
            this.FunctionCode = functioncode;
        }
        /// <summary>
        /// send message
        /// </summary>
        /// <param name="message">message needs to be sent</param>
        public void SendMessage(Message message)
        {
            message.FunctionCode = this.FunctionCode;
            message.Createtime = DateTime.Now;
            MessageArg arg = new MessageArg { MyMessage = message, IsCanceled = false };
            try
            {
                if (BeforeMessage != null) BeforeMessage(arg);
            }
            catch { }
            if (arg.IsCanceled) return;

            try
            {
                if (this.DatabaseEnable)
                {
                    EventEngine.SaveMessage(message);
                }
                if (this.EmailEnable)
                {
                    EventEngine.SendMail(message);
                }
                if (this.MessageEnable)
                {
                    EventEngine.SendMessage(message);
                }

            }
            catch (Exception ex)
            {
                if (AfterMessageError != null) AfterMessageError(arg,ex);
                return;
            }
            try
            {
                if (AfterMessage != null) AfterMessage(arg);
            }
            catch { }
        }
        #endregion

    }
}
